if (!Logger) var Logger = {};
if (!Logger.writeMessage)
{
	Logger.writeMessage = function (prefix, caller, obj, color) {
		var div = Logger.getDiv ();
		var line = document.createElement ("span");

		function getDate (showMillsecond) {
			var date = new Date ();
			var s = "";
			s += date.getFullYear();
			s += "-";
			var m = date.getMonth () + 1;
			s += m < 10 ? "0" + m : "" + m;
			s += "-";
			s += date.getDate () < 10 ? "0" + date.getDate () : "" + date.getDate ();
			s += " ";
			s += date.getHours () < 10 ? "0" + date.getHours () : "" + date.getHours ();
			s += ":";
			s += date.getMinutes () < 10 ? "0" + date.getMinutes () : "" + date.getMinutes ();
			s += ":";
			s += date.getSeconds () < 10 ? "0" + date.getSeconds () : "" + date.getSeconds ();
			if (showMillsecond) {
				s += ".";
				var ms = date.getMilliseconds ();
				if (ms < 10) s += "00" + ms;
				else if (ms < 100) s += "0" + ms;
				else s += ms;
			}
			return s;
		}

		var date_string = getDate(true);
		line.style.color = color;
		var text = (obj == null) ? "null" : obj.toString ();
		if (text.indexOf ("\n") != -1)
		{
			var lines = text.split ("\n");
			text = "";
			for (var i = 0; i < lines.length; i ++)
			{
				if (i != 0) text += "<br>";
				text += lines[i].replace (/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace (/</, '&lt;').replace (/>/, '&gt;');
			}
		}
		else 
			text = text.replace (/</g, '&lt;').replace (/>/g, '&gt;');
		line.innerHTML = '[' + getDate(true) + '][' + prefix + '][' + caller + '] ' + text;
		div.appendChild (line);
		div.appendChild (document.createElement ("br"));
		if (typeof (obj) == 'object') {
			var indent = "";
			for (var i = 0; i < date_string.length + 10; i ++) indent += "&nbsp;"
			for (var key in obj) {
				var value = obj [key];
				if (typeof (value) == 'function') continue;
				line = document.createElement ("span");
				line.style.color = color;
				line.innerHTML = indent + key + " -> " + obj [key] + "<br>";
				div.appendChild (line);
			}
		}
	}
}

Logger.DEBUG = 4;
Logger.INFO  = 3;
Logger.WARN  = 2;
Logger.ERROR = 1;

Logger.level = Logger.DEBUG;

if (!Logger.debug) {
	Logger.debug = function (obj) {
		if (Logger.level && Logger.level >= Logger.DEBUG)
			Logger.writeMessage ('DEBUG', __getCaller (Logger.debug), obj, '#996600');
	}
}

if (!Logger.info) {
	Logger.info = function (obj) {
		if (Logger.level && Logger.level >= Logger.INFO)
		Logger.writeMessage (' INFO', __getCaller (Logger.info), obj, 'black');
	}
}

if (!Logger.warn) {
	Logger.warn = function (obj) {
		if (Logger.level && Logger.level >= Logger.WARN)
		Logger.writeMessage (' WARN', __getCaller (Logger.warn), obj, 'orange');
	}
}

if (!Logger.error) {
	Logger.error = function (obj) {
		if (Logger.level >= Logger.ERROR)
		Logger.writeMessage ('FATAL', __getCaller (Logger.error), obj, 'red');
	}
}

if (!Logger.noop) {
	Logger.noop = function () { Logger.writeMessage ('NOOP', '', 'black'); }
}

if (!Logger.getDiv) {
	Logger.getDiv = function () {
		var div = document.getElementById ("debug");
		if (!div) {
			div = document.createElement ("div");
			div.id = 'debug';
			document.body.appendChild (div);
			div.style.fontFamily = "Courier New";
			div.style.fontSize = 12;
			div.style.width = "100%";
			div.style.overflow = 'auto';
			div.style.border = "1px solid black";
			div.style.backgroundColor = "lightyellow";
		}
		return div;
	}
}

function __getCaller (func) {
	if (!func) return null;
	return func.caller.name;
}